﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Effects;

namespace BreathingEffectDemo
{
    public class BreathingBorder : Border
    {
        public static readonly DependencyProperty IsBreathingProperty =
            DependencyProperty.Register(
                nameof(IsBreathing),
                typeof(bool),
                typeof(BreathingBorder),
                new PropertyMetadata(false, OnIsBreathingChanged));

        public static readonly DependencyProperty AnimationDurationProperty =
            DependencyProperty.Register(
                nameof(AnimationDuration),
                typeof(double),
                typeof(BreathingBorder),
                new PropertyMetadata(2.0));

        public static readonly DependencyProperty BorderOpacityFromProperty =
            DependencyProperty.Register(
                nameof(BorderOpacityFrom),
                typeof(double),
                typeof(BreathingBorder),
                new PropertyMetadata(1.0));

        public static readonly DependencyProperty BorderOpacityToProperty =
            DependencyProperty.Register(
                nameof(BorderOpacityTo),
                typeof(double),
                typeof(BreathingBorder),
                new PropertyMetadata(0.5));

        public static readonly DependencyProperty ShadowOpacityFromProperty =
            DependencyProperty.Register(
                nameof(ShadowOpacityFrom),
                typeof(double),
                typeof(BreathingBorder),
                new PropertyMetadata(0.6));

        public static readonly DependencyProperty ShadowOpacityToProperty =
            DependencyProperty.Register(
                nameof(ShadowOpacityTo),
                typeof(double),
                typeof(BreathingBorder),
                new PropertyMetadata(0.8));

        public static readonly DependencyProperty ShadowBlurFromProperty =
            DependencyProperty.Register(
                nameof(ShadowBlurFrom),
                typeof(double),
                typeof(BreathingBorder),
                new PropertyMetadata(10.0));

        public static readonly DependencyProperty ShadowBlurToProperty =
            DependencyProperty.Register(
                nameof(ShadowBlurTo),
                typeof(double),
                typeof(BreathingBorder),
                new PropertyMetadata(40.0));

        public bool IsBreathing
        {
            get => (bool)GetValue(IsBreathingProperty);
            set => SetValue(IsBreathingProperty, value);
        }

        public double AnimationDuration
        {
            get => (double)GetValue(AnimationDurationProperty);
            set => SetValue(AnimationDurationProperty, value);
        }

        public double BorderOpacityFrom
        {
            get => (double)GetValue(BorderOpacityFromProperty);
            set => SetValue(BorderOpacityFromProperty, value);
        }

        public double BorderOpacityTo
        {
            get => (double)GetValue(BorderOpacityToProperty);
            set => SetValue(BorderOpacityToProperty, value);
        }

        public double ShadowOpacityFrom
        {
            get => (double)GetValue(ShadowOpacityFromProperty);
            set => SetValue(ShadowOpacityFromProperty, value);
        }

        public double ShadowOpacityTo
        {
            get => (double)GetValue(ShadowOpacityToProperty);
            set => SetValue(ShadowOpacityToProperty, value);
        }

        public double ShadowBlurFrom
        {
            get => (double)GetValue(ShadowBlurFromProperty);
            set => SetValue(ShadowBlurFromProperty, value);
        }

        public double ShadowBlurTo
        {
            get => (double)GetValue(ShadowBlurToProperty);
            set => SetValue(ShadowBlurToProperty, value);
        }

        private Storyboard _breathingStoryboard;

        public BreathingBorder()
        {
            InitializeBreathingAnimation();
        }

        private static void OnIsBreathingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var border = (BreathingBorder)d;
            if ((bool)e.NewValue)
            {
                border.Visibility = Visibility.Visible;
                border.StartBreathingAnimation();
            }
            else
            {
                border.StopBreathingAnimation();
            }
        }

        private void InitializeBreathingAnimation()
        {
            _breathingStoryboard = new Storyboard
            {
                RepeatBehavior = RepeatBehavior.Forever,
                AutoReverse = true
            };

            var borderOpacityAnimation = new DoubleAnimation
            {
                From = BorderOpacityFrom,
                To = BorderOpacityTo,
                Duration = new Duration(TimeSpan.FromSeconds(AnimationDuration)),
                EasingFunction = new QuinticEase { EasingMode = EasingMode.EaseInOut }
            };
            Storyboard.SetTargetProperty(borderOpacityAnimation, new PropertyPath("(BorderBrush).(SolidColorBrush.Opacity)"));

            var shadowOpacityAnimation = new DoubleAnimation
            {
                From = ShadowOpacityFrom,
                To = ShadowOpacityTo,
                Duration = new Duration(TimeSpan.FromSeconds(AnimationDuration)),
                EasingFunction = new QuinticEase { EasingMode = EasingMode.EaseInOut }
            };
            Storyboard.SetTargetProperty(shadowOpacityAnimation, new PropertyPath("(UIElement.Effect).(DropShadowEffect.Opacity)"));

            var shadowBlurAnimation = new DoubleAnimation
            {
                From = ShadowBlurFrom,
                To = ShadowBlurTo,
                Duration = new Duration(TimeSpan.FromSeconds(AnimationDuration)),
                EasingFunction = new QuinticEase { EasingMode = EasingMode.EaseInOut }
            };
            Storyboard.SetTargetProperty(shadowBlurAnimation, new PropertyPath("(UIElement.Effect).(DropShadowEffect.BlurRadius)"));


            _breathingStoryboard.Children.Add(borderOpacityAnimation);
            _breathingStoryboard.Children.Add(shadowOpacityAnimation);
            _breathingStoryboard.Children.Add(shadowBlurAnimation);


            Storyboard.SetTarget(borderOpacityAnimation, this);
            Storyboard.SetTarget(shadowOpacityAnimation, this);
            Storyboard.SetTarget(shadowBlurAnimation, this);

        }

        private void StartBreathingAnimation()
        {
            if (Effect == null)
            {
                Effect = new DropShadowEffect
                {
                    Color = BorderBrush is SolidColorBrush brush ? brush.Color : Colors.Green,
                    ShadowDepth = 0,
                    BlurRadius = ShadowBlurFrom,
                    Opacity = ShadowOpacityFrom
                };
            }

            _breathingStoryboard.Begin(this, true);
        }

        private void StopBreathingAnimation()
        {
            _breathingStoryboard.Stop(this);
            this.Visibility = Visibility.Hidden;
        }
    }
}
